#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
新浪财经历史分红数据预处理脚本
功能：对爬取的新浪财经历史分红数据进行预处理，包括数据检查、日期处理、数据归一化等
"""

import pandas as pd
import numpy as np
import logging
import os

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

class SinaDividendPreprocessor:
    """新浪财经历史分红数据预处理类"""
    
    def __init__(self, input_file="新浪财经历史分红数据.xlsx", output_file="新浪财经历史分红数据_预处理.xlsx"):
        self.input_file = input_file
        self.output_file = output_file
        self.raw_data = None
        self.processed_data = None
    
    def load_data(self):
        """加载原始数据"""
        try:
            if not os.path.exists(self.input_file):
                logger.error(f"输入文件 {self.input_file} 不存在")
                return False
            
            self.raw_data = pd.read_excel(self.input_file)
            logger.info(f"成功加载数据，共有 {len(self.raw_data)} 行 {len(self.raw_data.columns)} 列")
            return True
        except Exception as e:
            logger.error(f"加载数据时发生异常: {str(e)}")
            return False
    
    def check_data_shape(self):
        """检查数据形状"""
        if self.raw_data is None:
            logger.warning("请先加载数据")
            return
        
        logger.info(f"数据形状: {self.raw_data.shape}")
        logger.info(f"数据列名: {list(self.raw_data.columns)}")
    
    def check_duplicates(self):
        """检查重复值"""
        if self.raw_data is None:
            logger.warning("请先加载数据")
            return
        
        # 检查整体重复行
        duplicate_rows = self.raw_data.duplicated().sum()
        logger.info(f"数据中共有 {duplicate_rows} 行完全重复的数据")
        
        # 检查特定列的重复值
        columns_to_check = ["代码", "名称", "详细"]
        for col in columns_to_check:
            if col in self.raw_data.columns:
                unique_count = self.raw_data[col].nunique()
                total_count = len(self.raw_data[col])
                duplicate_count = total_count - unique_count
                
                if duplicate_count > 0:
                    logger.info(f"列 '{col}' 中共有 {duplicate_count} 个重复值，唯一值数量: {unique_count}")
                    # 显示前5个重复的值
                    duplicate_values = self.raw_data[col][self.raw_data[col].duplicated()].head().tolist()
                    logger.info(f"列 '{col}' 中前5个重复的值: {duplicate_values}")
                else:
                    logger.info(f"列 '{col}' 中没有重复值")
            else:
                logger.warning(f"数据中不存在列 '{col}'")
    
    def show_head(self, n=5):
        """展示数据前n行"""
        if self.raw_data is None:
            logger.warning("请先加载数据")
            return
        
        logger.info(f"数据前 {n} 行:")
        print(self.raw_data.head(n))
        
        # 观察数据可能存在的问题
        logger.info("数据类型信息:")
        print(self.raw_data.dtypes)
        
        logger.info("缺失值统计:")
        print(self.raw_data.isnull().sum())
    
    def process_listing_date(self):
        """处理上市日期，提取年、月、日变量"""
        if self.processed_data is None:
            self.processed_data = self.raw_data.copy()
        
        if "上市日期" in self.processed_data.columns:
            try:
                # 尝试将上市日期转换为日期类型
                self.processed_data["上市日期"] = pd.to_datetime(self.processed_data["上市日期"], errors='coerce')
                
                # 提取年、月、日
                self.processed_data["上市年份"] = self.processed_data["上市日期"].dt.year
                self.processed_data["上市月份"] = self.processed_data["上市日期"].dt.month
                self.processed_data["上市日"] = self.processed_data["上市日期"].dt.day
                
                logger.info("成功处理上市日期，提取了年、月、日变量")
            except Exception as e:
                logger.error(f"处理上市日期时发生异常: {str(e)}")
        else:
            logger.warning("数据中不存在 '上市日期' 列")
    
    def normalize_numeric_variables(self):
        """对数值型变量进行数据归一化处理"""
        if self.processed_data is None:
            self.processed_data = self.raw_data.copy()
        
        numeric_columns = ["累计股息(%)", "年均股息(%)", "分红次数", "融资总额(亿元)"]
        normalized_columns = []
        
        for col in numeric_columns:
            if col in self.processed_data.columns:
                try:
                    # 尝试将列转换为数值型
                    # 处理可能包含百分号或其他符号的情况
                    if col in ["累计股息(%)", "年均股息(%)"]:
                        self.processed_data[col] = self.processed_data[col].str.replace('%', '').astype(float)
                    else:
                        self.processed_data[col] = pd.to_numeric(self.processed_data[col], errors='coerce')
                    
                    # 计算归一化值 (min-max归一化)
                    min_val = self.processed_data[col].min()
                    max_val = self.processed_data[col].max()
                    
                    if max_val > min_val:  # 避免除以0
                        normalized_col_name = f"{col}_归一化"
                        self.processed_data[normalized_col_name] = (self.processed_data[col] - min_val) / (max_val - min_val)
                        normalized_columns.append(normalized_col_name)
                        logger.info(f"成功对列 '{col}' 进行归一化处理")
                    else:
                        logger.warning(f"列 '{col}' 的最大值等于最小值，无法进行归一化处理")
                except Exception as e:
                    logger.error(f"处理列 '{col}' 时发生异常: {str(e)}")
            else:
                logger.warning(f"数据中不存在列 '{col}'")
        
        return normalized_columns
    
    def save_processed_data(self):
        """保存预处理后的数据"""
        try:
            if self.processed_data is None:
                logger.warning("没有预处理后的数据可保存")
                return False
            
            self.processed_data.to_excel(self.output_file, index=False)
            logger.info(f"预处理后的数据已成功保存到 {self.output_file}")
            return True
        except Exception as e:
            logger.error(f"保存预处理数据时发生异常: {str(e)}")
            return False
    
    def run_all_preprocessing(self):
        """运行所有预处理步骤"""
        logger.info("开始数据预处理")
        
        # 1. 加载数据
        if not self.load_data():
            return False
        
        # 2. 检查数据形状
        self.check_data_shape()
        
        # 3. 检查重复值
        self.check_duplicates()
        
        # 4. 展示数据前5行
        self.show_head()
        
        # 5. 处理上市日期
        self.process_listing_date()
        
        # 6. 对数值型变量进行归一化处理
        self.normalize_numeric_variables()
        
        # 7. 保存预处理后的数据
        return self.save_processed_data()


if __name__ == "__main__":
    """主函数"""
    preprocessor = SinaDividendPreprocessor()
    
    try:
        # 运行所有预处理步骤
        success = preprocessor.run_all_preprocessing()
        
        if success:
            logger.info("数据预处理完成")
        else:
            logger.error("数据预处理失败")
            
    except KeyboardInterrupt:
        logger.info("程序被用户中断")
    except Exception as e:
        logger.error(f"程序运行时发生异常: {str(e)}")